package search

import (
	"context"
	"encoding/json"
	"github.com/elastic/go-elasticsearch/v7/esapi"
	"github.com/pkg/errors"
	"io"
	"log"
	"math"
	"strings"
	"yangming-college/common/util"

	"yangming-college/app/speciality/cmd/v1/api/internal/svc"
	"yangming-college/app/speciality/cmd/v1/api/internal/types"

	"github.com/zeromicro/go-zero/core/logx"
)

type SearchLogic struct {
	logx.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewSearchLogic(ctx context.Context, svcCtx *svc.ServiceContext) *SearchLogic {
	return &SearchLogic{
		Logger: logx.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *SearchLogic) Search(paginator *util.Paginator, req *types.ReqSearch) (resp *types.SearchList, err error) {
	esClient := l.svcCtx.ESClinet

	var query map[string]interface{}
	switch req.Type {
	case 1:
		// 1_综合排序
		query = map[string]interface{}{
			"query": map[string]interface{}{
				"multi_match": map[string]interface{}{
					"query":     req.Key,
					"fields":    []string{"title", "description", "speciality_tags", "classification_tags", "customize_tags"},
					"fuzziness": "auto",
				},
			},
			// 添加综合排序的条件，可以根据需要进行调整
			"sort": []map[string]interface{}{
				{
					"_score": map[string]interface{}{
						"order": "desc",
					},
				},
			},
		}
	case 2:
		// 2_评分最高
		query = map[string]interface{}{
			"query": map[string]interface{}{
				"multi_match": map[string]interface{}{
					"query":     req.Key,
					"fields":    []string{"title", "description", "speciality_tags", "classification_tags", "customize_tags"},
					"fuzziness": "auto",
				},
			},
			// 添加评分最高排序的条件，可以根据需要进行调整
			"sort": []map[string]interface{}{
				{
					"_script": map[string]interface{}{
						"type": "number",
						"script": map[string]interface{}{
							"lang":   "painless",
							"source": "doc['score'].value / doc['numscore'].value",
						},
						"order": "desc",
					},
				},
			},
		}
	case 3:
		// 3_最多播放
		query = map[string]interface{}{
			"query": map[string]interface{}{
				"multi_match": map[string]interface{}{
					"query":     req.Key,
					"fields":    []string{"title", "description", "speciality_tags", "classification_tags", "customize_tags"},
					"fuzziness": "auto",
				},
			},
			// 添加最多播放排序的条件，可以根据需要进行调整
			"sort": []map[string]interface{}{
				{
					"view": map[string]interface{}{
						"order": "desc",
					},
				},
			},
		}
	case 4:
		// 4_最多收藏
		query = map[string]interface{}{
			"query": map[string]interface{}{
				"multi_match": map[string]interface{}{
					"query":     req.Key,
					"fields":    []string{"title", "description", "speciality_tags", "classification_tags", "customize_tags"},
					"fuzziness": "auto",
				},
			},
			// 添加最多收藏排序的条件，可以根据需要进行调整
			"sort": []map[string]interface{}{
				{
					"collection": map[string]interface{}{
						"order": "desc",
					},
				},
			},
		}
	case 5:
		// 5_最近更新
		query = map[string]interface{}{
			"query": map[string]interface{}{
				"multi_match": map[string]interface{}{
					"query":     req.Key,
					"fields":    []string{"title", "description", "speciality_tags", "classification_tags", "customize_tags"},
					"fuzziness": "auto",
				},
			},
			// 添加最近更新排序的条件，可以根据需要进行调整
			"sort": []map[string]interface{}{
				{
					"update_time": map[string]interface{}{
						"order": "desc",
					},
				},
			},
		}
	default:
		// 默认综合排序
		query = map[string]interface{}{
			"query": map[string]interface{}{
				"multi_match": map[string]interface{}{
					"query":     req.Key,
					"fields":    []string{"title", "description", "speciality_tags", "classification_tags", "customize_tags"},
					"fuzziness": "auto",
				},
			},
			// 默认排序条件，可以根据需要进行调整
			"sort": []map[string]interface{}{
				{
					"_score": map[string]interface{}{
						"order": "desc",
					},
				},
			},
		}

	}

	reqBody, err := json.Marshal(query)
	if err != nil {
		log.Fatalf("Error marshalling query: %s", err)
		return nil, errors.Wrapf(err, "speciality v1 api Search error 1")
	}

	from := paginator.Offset()
	size := paginator.PerPage()
	searchReq := esapi.SearchRequest{
		Index: []string{"course"},
		Body:  strings.NewReader(string(reqBody)),
		From:  &from, // Set the starting index for pagination
		Size:  &size, // Set the number of results per page
	}

	res, err := searchReq.Do(context.Background(), esClient)
	if err != nil {
		log.Fatalf("Error performing search request: %s", err)
		return nil, errors.Wrapf(err, "speciality v1 api Search error 2")
	}
	defer res.Body.Close()

	if res.IsError() {
		log.Fatalf("Search request failed: %s", res.Status())
		return nil, errors.Wrapf(err, "speciality v1 api Search error 3")
	}

	// 处理搜索结果
	var response map[string]interface{}
	if err := parseResponseBody(res.Body, &response); err != nil {
		log.Fatalf("Error parsing response body: %s", err)
		return nil, errors.Wrapf(err, "speciality v1 api Search error 4")
	}

	hits, ok := response["hits"].(map[string]interface{})["hits"].([]interface{})
	if !ok {
		log.Fatal("Invalid hits structure in response")
		return nil, errors.Wrapf(err, "speciality v1 api Search error 5")
	}

	var courses []types.RepSearchCourse
	for _, hit := range hits {
		source, ok := hit.(map[string]interface{})["_source"].(map[string]interface{})
		if !ok {
			log.Fatal("Invalid source structure in hit")
			return nil, errors.Wrapf(err, "speciality v1 api Search error 6")
		}

		course := types.RepSearchCourse{
			Id:           hit.(map[string]interface{})["_id"].(string),
			Title:        source["title"].(string),
			CoverAddress: source["coverurl"].(string),
			Tags:         "",
			Description:  source["description"].(string),
			Score:        source["score"].(float64) / source["numscore"].(float64),
			Uid:          int64(source["uid"].(float64)),
			Uname:        "", // Add Uname if available in the response
		}

		courses = append(courses, course)
	}

	// Now you have the parsed courses, and you can create a SearchList
	searchList := types.SearchList{
		Courses:   courses,
		Total:     int64(response["hits"].(map[string]interface{})["total"].(map[string]interface{})["value"].(float64)),
		TotalPage: int64(math.Ceil(response["hits"].(map[string]interface{})["total"].(map[string]interface{})["value"].(float64) / float64(req.Size))), // Modify this based on your pagination logic
	}

	return &searchList, nil
}

func parseResponseBody(body io.Reader, target interface{}) error {
	decoder := json.NewDecoder(body)
	return decoder.Decode(target)
}
